﻿using CSharp.ConsoleTools.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSharp.ConsoleTools
{
	#region event stuff
	#region         delegates
	//callback delegate
	public delegate void MenuSelectCallbackDelegate();
	#endregion

	#region			menu command args
	public class MenuCommandArgs
	{
		/// <summary>
		/// case sensitive command string that is recognized by the menu loop 
		/// </summary>
		/// <example>
		/// "a"
		/// "MakeThis"
		/// "MakeThat"
		/// "Quit"
		/// "x"
		/// </example>
		public string Command { get; set; }

		/// <summary>
		/// Description string that is shown in the menu content area. Should also contain the described command in some way.
		/// </summary>
		/// <example>
		/// "a: Do Something"
		/// "Do something else (MakeThis)"
		/// "x: Quit application"
		/// </example>
		public string Description { get; set; }

		/// <summary>
		/// CommandCallbackDelegate function that is called by the menu loop when the command is recognized.
		/// </summary>
		/// <example>
		/// "new MenuSelectCallbackDelegate(MenuCommandCallback_Quit)"
		/// </example>
		public MenuSelectCallbackDelegate CommandCallback { get; set; }
	}
	#endregion
	#endregion

	public sealed class MenuHandler
    {
        #region declares
        // singleton member
        static readonly MenuHandler _instance = new MenuHandler();

        // menu area member
        private ConsoleArea _menuArea;

        // command list
		private Dictionary<string, MenuCommandArgs> _dictMenuCommands = new Dictionary<string, MenuCommandArgs>();

		// internal vars
		private bool _fLoopRunning = false;
		#endregion



        #region constructor
        // singleton private constructor
        private MenuHandler()
        {
        }
        #endregion



        #region private functions
        private void _menuLoop()
        {
			//check if there are commands
			if (_dictMenuCommands.Count > 0)
			{
				//prepare input var
				string strInput="";

				//first render menu
				Area.Render();

				//then go to endless loop
				while (_fLoopRunning)
				{
					//set cursor to "input position"
					_initInputPosition();
					
					//wait for input
					strInput = Console.ReadLine();

					//see if a command was input
					foreach (KeyValuePair<string, MenuCommandArgs> kvp in _dictMenuCommands)
					{
						//if yes, simply call CommandCallback delegate
						if (kvp.Key == strInput)
						{
							kvp.Value.CommandCallback();
						}
					}
				}
			}
        }

		private void _initInputPosition()
		{
			//generate empty string
			string strEmpty = "";
			strEmpty = strEmpty.PadLeft(Area.ContentWidth - 1, ' ');

			//first off clear position
			Console.SetCursorPosition(Area.ContentLeft, Area.ContentTop + Area.ContentHeight - 1);
			Console.Write(strEmpty);

			//then generate input "field"
			Console.SetCursorPosition(Area.ContentLeft, Area.ContentTop + Area.ContentHeight - 1);
			Console.Write(Settings.Default.Prompt.ToString());
			;
		}
        #endregion



        #region properties
        // singleton instance getter
        public static MenuHandler Instance { get { return _instance; } }

        // menu area
        public ConsoleArea Area { get { return _menuArea; } }

        // command list
		public Dictionary<string, MenuCommandArgs> MenuCommands { get { return _dictMenuCommands; } }
        #endregion



        #region methods
        public void InitMenu(
            ConsoleArea MenuArea)
        {
            _menuArea = MenuArea;
        }

		public void Render()
		{
            Area.ClearContent();
            foreach (KeyValuePair<string,MenuCommandArgs> kvp in MenuCommands)
            {
                Area.AddContent(kvp.Value.Description);
            }
			Area.Render();
		}

		public void Activate()
        {
			_fLoopRunning = true;
			_menuLoop();
        }

		public void Deactivate()
		{
			_fLoopRunning = false;
		}

		#region			menu commands
		public void ClearMenuCommands()
		{
			_dictMenuCommands.Clear();
		}

		public void AddMenuCommand(
			MenuCommandArgs ca)
		{
			if (!_dictMenuCommands.ContainsKey(ca.Command))
			{
				_dictMenuCommands.Add(ca.Command, ca);
				Area.AddContent(ca.Description);
			}
		}

		public void RemoveMenuCommand(
			string Command)
		{
			if (_dictMenuCommands.ContainsKey(Command))
			{
				Area.RemoveContent(_dictMenuCommands[Command].Description);
				_dictMenuCommands.Remove(Command);
			}
		}
		#endregion
		#endregion
	}
}
